home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Internet / News / Alexandra.0.82 / Source / Decoding.subproj / uudecode.c < prev   
Encoding:
C/C++ Source or Header  |  1996-01-30  |  11.5 KB  |  543 lines

  1. /* $Id: uudecode.c,v 1.1.1.1 1996/01/31 13:44:34 alex Exp $
  2.  *
  3.  * $Log: uudecode.c,v $
  4.  * Revision 1.1.1.1  1996/01/31 13:44:34  alex
  5.  * Importierte Source, Version 0.82 von Constantin
  6.  *
  7.  * Revision 4.4  1991/09/09  20:27:37  sob
  8.  * release 4.4
  9.  *
  10.  * Altered to work with NeXT's NXStreams.
  11.  * Altering done by Todd Thomas, July 4, 1995.
  12.  *
  13.  * Decode one or more uuencoded articles back to binary form.
  14.  * Adapted to rn 4.4 by Stan Barber
  15.  * Trn version created by Wayne Davison.
  16.  * Adapted from the nn version by Kim Storm.
  17.  * From the Berkeley original, modified by MSD, RDR, JPHD & WLS.
  18.  */
  19. /*
  20.  * This software is Copyright 1991 by Stan Barber. 
  21.  *
  22.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  23.  * use this software as long as: there is no monetary profit gained
  24.  * specifically from the use or reproduction of this software, it is not
  25.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  26.  * included prominently in any copy made. 
  27.  *
  28.  * The author make no claims as to the fitness or correctness of this software
  29.  * for any use whatsoever, and it is provided as is. Any use of this software
  30.  * is at the user's own risk. 
  31.  */
  32.  
  33. #include <sys/param.h>
  34. #include <string.h>
  35. #include <libc.h>
  36. #include <stdlib.h>
  37. #include <ctype.h>
  38.  
  39. //#include "EXTERN.h"
  40. //#include "common.h"
  41. //#include "respond.h"
  42. #include "decode.h"
  43.  
  44. #define MAXCHAR 256
  45. #define NORMLEN 64    /* allows for 84 encoded chars per line */
  46.  
  47. #define SEQMAX 'z'
  48. #define SEQMIN 'a'
  49.  
  50. #define strNE(s1,s2) (strcmp(s1,s2))
  51. #define strEQ(s1,s2) (!strcmp(s1,s2))
  52. #define strnNE(s1,s2,l) (strncmp(s1,s2,l))
  53. #define strnEQ(s1,s2,l) (!strncmp(s1,s2,l))
  54.  
  55. /* Forward declarations */
  56. static int decode_line (char *);
  57. static void inittbls (void);
  58. static void gettable (NXStream *in);
  59. static char* NXgets (char *buf, long buflen, NXStream *theStream);
  60. // static void decode_end();
  61.  
  62. /* Some declarations that were in decode.h */
  63. static FILE* decode_fp = NULL;
  64. static char decode_fname[MAXPATHLEN+1];
  65. static char decode_dest[MAXPATHLEN+1];
  66.  
  67. /* Temporary */
  68. static char *extractdest = NULL;
  69.  
  70. static char seqc;
  71. static int first, secnd, check, numl;
  72.  
  73. static char blank;
  74. static int chtbl[MAXCHAR], cdlen[NORMLEN + 3];
  75. static int state;
  76. static BOOL Xflag;
  77. static int expecting_part;
  78.  
  79. const char* decodeDepositPathname()
  80. {
  81.     if(!extractdest)
  82.         return "\tmp";
  83.     
  84.     return extractdest;
  85. }
  86.  
  87. void setDecodeDepositPathname(const char* aPathname)
  88. {
  89.     if (aPathname){
  90.         if(extractdest)
  91.             free (extractdest);
  92.         extractdest=malloc((strlen(aPathname)+2)*sizeof(char));
  93.         strcpy(extractdest, aPathname);
  94.     }
  95. }
  96.  
  97. void uud_start()
  98. {
  99.     Xflag = FALSE;
  100.     expecting_part = 0;
  101.     seqc = SEQMAX;
  102.     check = 1;
  103.     first = 1;
  104.     secnd = 0;
  105.     state = FIND_BEGIN;
  106.     decode_fp = NULL;
  107. }
  108.  
  109. // This is a hack because you can't tell if uudecode failed when
  110. // you only expect a single part. If it doesn't find the "end"
  111. // it assumes that it is continued and returns success. This way we
  112. // can look into the state after a uudecode to see what it's last
  113. // state was.
  114.  
  115. int uudecode_state()
  116. {
  117.     return state;
  118. }
  119.  
  120. int uudecode(NXStream *in)
  121. {
  122.     int mode, onedone, lens;
  123.     char buff[LBUFLEN];
  124.  
  125.  
  126.     numl = onedone = 0;
  127.  
  128.     if (state == FIND_BEGIN)
  129.     inittbls();
  130.  
  131.     /*
  132.      * search for header or translation table line.
  133.      */
  134.  
  135.     while ((state & NO_ADVANCE) || NXgets(buff, sizeof buff, in) != Nullch) {
  136.     numl++;
  137.  
  138.     switch (state) {
  139.      case NEW_BEGIN:
  140.         if (decode_fp != Nullfp) {
  141.         if (expecting_part) {
  142.             register int got_part = 0;
  143.  
  144.             if (strnEQ(buff + 6, "part ", 5)) {
  145.             register char *bp;
  146.  
  147.             for (bp = buff + 11; islower(*bp); bp++)
  148.                 got_part = got_part * 26 + *bp - 'a';
  149.             }
  150.             if (expecting_part == got_part) {
  151.             state = DECODE_TEXT;
  152.             break;
  153.             }
  154.             printf("Expecting part %d; got part %d.\n",
  155.              expecting_part + 1, got_part + 1);
  156.             if (got_part) {
  157.             state = SKIP_LEADING;
  158.             return -1;
  159.             }
  160.         }
  161.         decode_end();
  162.         sleep(2);
  163.         Xflag = FALSE;
  164.         expecting_part = 0;
  165.         }
  166.         state = FIND_BEGIN;
  167.         /* fall thru */
  168.  
  169.      case FIND_BEGIN:
  170.      case AFTER_ERROR_FIND_BEGIN:
  171.         if (strnEQ(buff, "table", 5)) {
  172.         gettable(in);
  173.         continue;
  174.         }
  175.  
  176.         if (strnEQ(buff, "begin ", 6)
  177.          || strnEQ(buff, "Xbegin ", 7)) {
  178.         lens = strlen(buff)-1;
  179.         if (buff[lens] == '\n')
  180.             buff[lens] = '\0';
  181.  
  182.         if(sscanf(buff+6,"%o%s", &mode, decode_fname) != 2) {
  183.             register char *bp = buff + 6;
  184.  
  185.             if (*bp == ' ')
  186.             bp++;
  187.             if (strnEQ(bp, "part ", 5)) {
  188.             register int got_part = 0;
  189.  
  190.             for (bp = bp + 5; islower(*bp); bp++)
  191.                 got_part = got_part * 26 + *bp - 'a';
  192.             printf("Expecting part 1; got part %d.\n",
  193.                 got_part + 1);
  194.             return -1;
  195.             }
  196.             continue;
  197.         }
  198.  
  199.         Xflag = (*buff == 'X');
  200.  
  201.         sprintf(decode_dest, "%s/%s",decodeDepositPathname(), decode_fname);
  202.  
  203.         if ((decode_fp = fopen(decode_dest, FOPEN_WB)) == Nullfp) {
  204.             printf("Cannot create file: %s\n", decode_dest);
  205.             goto err;
  206.         }
  207.         chmod(decode_dest, mode);
  208.         printf("Decoding: %s\n", decode_fname);
  209.         state = DECODE_TEXT;
  210.         }
  211.         continue;
  212.  
  213.      case SKIP_LEADING:
  214.         state = decode_line(buff);
  215.         continue;
  216.  
  217.      case DECODE_TEXT:
  218.         state = decode_line(buff);
  219.         onedone = 1;
  220.         continue;
  221.  
  222.      case FOUND_END:
  223.         fclose(decode_fp);
  224.         decode_fp = Nullfp;
  225.         Xflag = FALSE;
  226.         expecting_part = 0;
  227.         state = FIND_BEGIN;
  228.         printf("Done.\n");
  229.         continue;
  230.  
  231.      case SKIP_TRAILING:
  232.         printf("(Continued)\n");
  233.         state = SKIP_LEADING;
  234.         return 0;
  235.  
  236.      case DECODE_ERROR:
  237.         state = SKIP_TRAILING;
  238.         continue;
  239.  
  240.      case OTHER_ERROR:
  241.         fclose(decode_fp);
  242.         decode_fp = Nullfp;
  243.         Xflag = FALSE;
  244.         expecting_part = 0;
  245.         state = AFTER_ERROR_FIND_BEGIN;
  246.         goto err;
  247.     }
  248.     }
  249.  
  250.     if (onedone) {
  251.     if (state == DECODE_TEXT) {
  252.         printf("(Continued)\n");
  253.         state = SKIP_LEADING;
  254.     }
  255.     return 0;
  256.     }
  257.  
  258.     if (state == AFTER_ERROR_FIND_BEGIN)
  259.     return -1;
  260.     printf("Couldn't find anything to decode.\n");
  261.  
  262.  err:
  263.     sleep(2);
  264.     return -1;
  265. }
  266.  
  267. /*
  268.  * decode one line and write it out using decode_fp
  269.  */
  270.  
  271. static int decode_line(char *buff)
  272. {
  273.     char outl[LBUFLEN];
  274.     register char *bp, *ut;
  275.     register int *trtbl = chtbl;
  276.     register int n;
  277.     register int blen;        /* binary length (from decoded file) */
  278.     register int rlen;        /* calculated input line length */
  279.     register int len;        /* actual input line length */
  280.     register int dash;        /* number of '-'s encountered on a line */
  281.                 /* If it's too high, we reject the line */
  282.  
  283. #   define REJECT(buf,rlen,len) /* Comment for makedepend to     \
  284.                 ** ignore the backslash above */ \
  285.     ((*buf == 'M' && len > rlen + 5) \
  286.      || (*buf != 'M' && len != rlen && len != rlen+1) \
  287.      || (strnEQ(buf, "BEGIN", 5)) \
  288.      || (strnEQ(buf, "END", 3)))
  289.  
  290.     if (Xflag) {
  291.     if (*buff == 'X')
  292.         buff++;
  293.     else
  294.         *buff = 'x';    /* force a mis-parse of a non-x'ed line */
  295.     }
  296.     len = strlen(buff);
  297.     if (--len <= 0)
  298.     return state;
  299.  
  300.     buff[len] = '\0';
  301.  
  302.     /*
  303.      * Get the binary line length.
  304.      */
  305.     if ((blen = trtbl[buff[0]]) < 0) {
  306.     if (state == SKIP_LEADING) {
  307.         if (strnEQ(buff, "begin ", 6))
  308.         return NEW_BEGIN;
  309.  
  310.         return SKIP_LEADING;
  311.     }
  312.     /*
  313.      * end of uuencoded file ?
  314.      */
  315.     if (strnEQ(buff, "end", 3))
  316.         return FOUND_END;
  317.  
  318.     /*
  319.      * end of current file ? : get next one.
  320.      */
  321.     if (strnEQ(buff, "include ", 8)) {
  322.         for (bp = buff + 8; *bp; bp++) {
  323.         if (bp[0] == '.' && bp[1] == 'u') {
  324.             expecting_part = (bp[2] - 'a') * 26 + bp[3] - 'a';
  325.             break;
  326.         }
  327.         }
  328.     }
  329.  
  330.     /*
  331.      * trailing garbage
  332.      */
  333.     return SKIP_TRAILING;
  334.     }
  335.  
  336.     rlen = cdlen[blen];
  337.     if (state == SKIP_LEADING && REJECT(buff,rlen,len))
  338.     return SKIP_LEADING;
  339.  
  340.     /*
  341.      * Is it the empty line before the end line ?
  342.      */
  343.     if (blen == 0)
  344.     return state;
  345.  
  346.     if (REJECT(buff,rlen,len))
  347.     return SKIP_TRAILING;
  348.  
  349.     /*
  350.      * Pad with blanks.
  351.      */
  352.     for (bp = buff + len, n = rlen - len; --n >= 0; )
  353.     *bp++ = blank;
  354.  
  355.     /*
  356.      * Verify
  357.      */
  358.     for (n = rlen, bp = buff, dash = 0; --n >= 0; bp++) {
  359.     if (trtbl[*bp] < 0) {
  360.         if (state == SKIP_LEADING)
  361.         return SKIP_LEADING;
  362.         return DECODE_ERROR;
  363.     }
  364.     if (*bp == '-')
  365.         dash++;
  366.     }
  367.     if (dash * 100 / rlen > 33)        /* more than 1/3 dashes? */
  368.     if (state == SKIP_LEADING)
  369.         return SKIP_LEADING;    /* -> reject */
  370.     else
  371.         return SKIP_TRAILING;
  372.  
  373.     /*
  374.      * Check for uuencodes that append a 'z' to each line....
  375.      */
  376.     if (check)
  377.     if (secnd) {
  378.         secnd = 0;
  379.         if (buff[rlen] == SEQMAX)
  380.         check = 0;
  381.     } else if (first) {
  382.         first = 0;
  383.         secnd = 1;
  384.         if (buff[rlen] != SEQMAX)
  385.         check = 0;
  386.     }
  387.  
  388.     /*
  389.      * There we check.
  390.      */
  391.     if (check) {
  392.     if (buff[rlen] != seqc) {
  393.         if (state == SKIP_LEADING)
  394.         return SKIP_LEADING;
  395.         return DECODE_ERROR;
  396.     }
  397.  
  398.     if (--seqc < SEQMIN)
  399.         seqc = SEQMAX;
  400.     }
  401.  
  402.     /*
  403.      * output a group of 3 bytes (4 input characters).
  404.      * the input chars are pointed to by p, they are to
  405.      * be output to file f. blen is used to tell us not to
  406.      * output all of them at the end of the file.
  407.      */
  408.     ut = outl;
  409.     n = blen;
  410.     bp = &buff[1];
  411.     while (--n >= 0) {
  412.     *(ut++) = trtbl[*bp] << 2 | trtbl[bp[1]] >> 4;
  413.     if (n > 0) {
  414.         *(ut++) = (trtbl[bp[1]] << 4) | (trtbl[bp[2]] >> 2);
  415.         n--;
  416.     }
  417.     if (n > 0) {
  418.         *(ut++) = trtbl[bp[2]] << 6 | trtbl[bp[3]];
  419.         n--;
  420.     }
  421.     bp += 4;
  422.     }
  423.     if (fwrite(outl, 1, blen, decode_fp) <= 0) {
  424.     printf("Error on writing decoded file\n");
  425.     return OTHER_ERROR;
  426.     }
  427.  
  428.     return DECODE_TEXT;
  429. }
  430.  
  431.  
  432.  
  433. /*
  434.  * Install the table in memory for later use.
  435.  */
  436. static void inittbls()
  437. {
  438.     register int i, j;
  439.  
  440.     /*
  441.      * Set up the default translation table.
  442.      */
  443.     for (i = 0; i < ' '; i++)
  444.     chtbl[i] = -1;
  445.     for (i = ' ', j = 0; i < ' ' + 64; i++, j++)
  446.     chtbl[i] = j;
  447.     for (i = ' ' + 64; i < MAXCHAR; i++)
  448.     chtbl[i] = -1;
  449.     chtbl['`'] = chtbl[' '];    /* common mutation */
  450.     chtbl['~'] = chtbl['^'];    /* another common mutation */
  451.     blank = ' ';
  452.     /*
  453.      * set up the line length table, to avoid computing lotsa * and / ...
  454.      */
  455.     cdlen[0] = 1;
  456.     for (i = 1, j = 5; i <= NORMLEN; i += 3, j += 4)
  457.     cdlen[i] = (cdlen[i + 1] = (cdlen[i + 2] = j));
  458. }
  459.  
  460. static void gettable(NXStream *in)
  461. {
  462.     char buff[LBUFLEN];
  463.     register int c, n = 0;
  464.     register char *cpt;
  465.  
  466.     for (c = 0; c < MAXCHAR; c++)
  467.     chtbl[c] = -1;
  468.  
  469.     for (;;) {
  470.     if (NXgets(buff, sizeof buff, in) == Nullch) {
  471.         printf("EOF while in translation table.\n");
  472.         return;
  473.     }
  474.     numl++;
  475.     if (strnEQ(buff, "begin", 5)) {
  476.         printf("Incomplete translation table.\n");
  477.         return;
  478.     }
  479.     cpt = buff + strlen(buff) - 1;
  480.     *cpt = ' ';
  481.     while (*cpt == ' ') {
  482.         *cpt = 0;
  483.         cpt--;
  484.     }
  485.     cpt = buff;
  486.     while (c = *cpt) {
  487.         if (chtbl[c] != -1) {
  488.         printf("Duplicate char in translation table.\n");
  489.         return;
  490.         }
  491.         if (n == 0)
  492.         blank = c;
  493.         chtbl[c] = n++;
  494.         if (n >= 64)
  495.         return;
  496.         cpt++;
  497.     }
  498.     }
  499. }
  500.  
  501.  
  502. char* NXgets (char *buf, long buflen, NXStream *theStream)
  503. {
  504.     /* Simulates fgets using NXStreams. Takes the same types of args
  505.        and returns the same values. */
  506.     int bWritten;
  507.     char inChar;
  508.     
  509.     if (!buf || buflen < 1) {
  510.     return NULL;
  511.     }
  512.     
  513.     bWritten = 0;
  514.     inChar = '\0';
  515.     memset(buf, 0, buflen);
  516.     
  517. //    while (!NXAtEOS(theStream) && ((inChar = NXGetc(theStream)) != '\n') &&
  518. //       (inChar != EOF)) {
  519.     while (!NXAtEOS(theStream) && (inChar != EOF)) {    
  520.     inChar = NXGetc(theStream);
  521.     if (bWritten == buflen-1) {
  522.         return buf;
  523.     }
  524.     *(buf+bWritten) = inChar;
  525.     bWritten++;
  526.     if (inChar == '\n') {
  527.         break;
  528.     }
  529.     }
  530.     return (!NXAtEOS(theStream)) ? buf : NULL;
  531. }
  532.  
  533.     
  534. void decode_end()
  535. {
  536.     if (decode_fp != Nullfp) {
  537.     fclose(decode_fp);
  538.     decode_fp = Nullfp;
  539.     printf("\n%s INCOMPLETE -- removed.\n", decode_dest);
  540.     unlink(decode_dest);
  541.     }
  542. }
  543.